#include "Complexe.h"

Complexe::Complexe() : Constante(COMPLEX)
{
this->type=COMPLEX;
        this->re = new Entier(0);
        this->im = new Entier(1);
}

Complexe::Complexe(const Complexe& c) : Constante(COMPLEX){

        switch(c.re->getType()){
                case Constante::INTEGER:
        this->re = new Entier(*static_cast<Entier*>(c.re));
                break;
                case Constante::RATIONNAL:
        this->re = new Rationnel(*static_cast<Rationnel*>(c.re));
                break;
                case Constante::REAL:
        this->re = new Reel(*static_cast<const Reel*>(c.re));
                break;
        }

        switch(c.im->getType()){
                case Constante::INTEGER:
        this->im = new Entier(*static_cast<const Entier*>(c.im));
                break;
                case Constante::RATIONNAL:
        this->im = new Rationnel(*static_cast<const Rationnel*>(c.im));
                break;
                case Constante::REAL:
        this->im = new Reel(*static_cast<const Reel*>(c.im));
                break;
        }
}

Complexe::Complexe(const NonComplexe*n1,const NonComplexe*n2) : Constante(COMPLEX){
this->type=COMPLEX;

        switch(n1->getType()){
                case Constante::INTEGER:
        this->re = new Entier(*static_cast<const Entier*>(n1));
                break;
                case Constante::RATIONNAL:
        this->re = new Rationnel(*static_cast<const Rationnel*>(n1));
                break;
                case Constante::REAL:
        this->re = new Reel(*static_cast<const Reel*>(n1));
                break;
        }

        switch(n2->getType()){
                case Constante::INTEGER:
        this->im = new Entier(*static_cast<const Entier*>(n2));
                break;
                case Constante::RATIONNAL:
        this->im = new Rationnel(*static_cast<const Rationnel*>(n2));
                break;
                case Constante::REAL:
        this->im = new Reel(*static_cast<const Reel*>(n2));
                break;
        }
}


Complexe::Complexe(const Entier& i) : Constante(COMPLEX){
this->type=COMPLEX;
        this->re = new Entier(i);
        this->im = new Entier(0);
}
Complexe::Complexe(const Rationnel& f) : Constante(COMPLEX){
this->type=COMPLEX;
        this->re = new Rationnel(f);
        this->im = new Entier(0);
}
Complexe::Complexe(const Reel& r) : Constante(COMPLEX){
this->type=COMPLEX;
        this->re = new Reel(r);
        this->im = new Entier(0);
}

Constante* Complexe::operator+(const Constante& c)const{
        switch(c.getType()){
                case Constante::INTEGER:
        return *this+Complexe(static_cast<const Entier&>(c));
                break;
                case Constante::RATIONNAL:
        return *this+Complexe(static_cast<const Rationnel&>(c));
                break;
                case Constante::REAL:
        return *this+Complexe(static_cast<const Reel&>(c));
                break;
                case Constante::COMPLEX:
        return new Complexe(static_cast<NonComplexe*>(Addition::apply(*this->re,*static_cast<const Complexe&>(c).re)),
                           static_cast<NonComplexe*>(Addition::apply(*this->im,*static_cast<const Complexe&>(c).im)));
                break;
        }
}

Constante* Complexe::operator*(const Constante& c)const{

        switch(c.getType()){
                case Constante::INTEGER:
        return new Complexe(static_cast<NonComplexe*>(Multiplcation::apply(*this->re,static_cast<const Entier&>(c))),
                           static_cast<NonComplexe*>(Multiplcation::apply(*this->im,static_cast<const Entier&>(c))));
                case Constante::RATIONNAL:
        return new Complexe(static_cast<NonComplexe*>(Multiplcation::apply(*this->re,static_cast<const Rationnel&>(c))),
                           static_cast<NonComplexe*>(Multiplcation::apply(*this->im,static_cast<const Rationnel&>(c))));
                case Constante::REAL:
        return new Complexe(static_cast<NonComplexe*>(Multiplcation::apply(*this->re,static_cast<const Reel&>(c))),
                           static_cast<NonComplexe*>(Multiplcation::apply(*this->im,static_cast<const Reel&>(c))));
                break;
                case Constante::COMPLEX:
        return new Complexe(
                static_cast<const NonComplexe*>(
                        Soustraction::apply(
                                *Multiplcation::apply(*this->re,*static_cast<const Complexe&>(c).re),
                                *Multiplcation::apply(*this->im,*static_cast<const Complexe&>(c).im)
                        )
                ),
                static_cast<const NonComplexe*>(
                        Addition::apply(
                                *Multiplcation::apply(*this->re,*static_cast<const Complexe&>(c).im),
                                *Multiplcation::apply(*this->im,*static_cast<const Complexe&>(c).re)
                        )
                )
                );
                break;
        }
}

Constante* Complexe::operator-(const Constante& c)const{

        switch(c.getType()){
                case Constante::INTEGER:
        return *this-Complexe(static_cast<const Entier&>(c));
                case Constante::RATIONNAL:
        return *this-Complexe(static_cast<const Rationnel&>(c));
                case Constante::REAL:
        return *this-Complexe(static_cast<const Reel&>(c));
                break;
                case Constante::COMPLEX:
        return new Complexe(static_cast<NonComplexe*>(Soustraction::apply(*this->re,*static_cast<const Complexe&>(c).re)),
                           static_cast<NonComplexe*>(Soustraction::apply(*this->im,*static_cast<const Complexe&>(c).im)));
                break;
        }
}

Constante* Complexe::operator/(const Constante& c)const{

        switch(c.getType()){
                case Constante::INTEGER:
        return *this/Complexe(static_cast<const Entier&>(c));
                case Constante::RATIONNAL:
        return *this/Complexe(static_cast<const Rationnel&>(c));
                case Constante::REAL:
        return *this/Complexe(static_cast<const Reel&>(c));
                break;
                case Constante::COMPLEX:

        return new Complexe(
                static_cast<NonComplexe*>(
                        Division::apply(
                                *Addition::apply(
                                      *Multiplcation::apply(*this->re,*static_cast<const Complexe&>(c).re),
                                     *Multiplcation::apply(*this->im,*static_cast<const Complexe&>(c).im)
                                )
                           ,
                                *Addition::apply(
                                        *Multiplcation::apply(*static_cast<const Complexe&>(c).re,*static_cast<const Complexe&>(c).re),
                                        *Multiplcation::apply(*static_cast<const Complexe&>(c).im,*static_cast<const Complexe&>(c).im)
                                )
                        )
                ),
                static_cast<NonComplexe*>(
                        Division::apply(
                                *Soustraction::apply(
                                        *Multiplcation::apply(*this->im,*static_cast<const Complexe&>(c).re),
                                        *Multiplcation::apply(*this->re,*static_cast<const Complexe&>(c).im)
                                )
                           ,
                                *Addition::apply(
                                        *Multiplcation::apply(*static_cast<const Complexe&>(c).re,*static_cast<const Complexe&>(c).re),
                                        *Multiplcation::apply(*static_cast<const Complexe&>(c).im,*static_cast<const Complexe&>(c).im)
                                )
                        )
                )
                );
                break;
        }
}

Constante* Complexe::operator-()const{
        return new Complexe((const NonComplexe*)-(*this->re),(const NonComplexe*)-(*this->im));
}

Complexe::~Complexe(){
        if(this->re)
                delete this->re;

        if(this->im)
                delete this->im;
}
